package scalab.core.dependencies
import scala.collection.mutable.HashMap
import scalab.utils.Pathname
import java.io.File 

abstract class Dependency(p: String) extends Resource(p){
	private def this() = this(".")
  def lacks: Boolean
	//override val canonicalpath: String = this.getCanonicalPath
	def sameResource(that: Resource): Boolean = super.equals(that)
	def sameResource(that: java.io.File): Boolean = 
		scalab.utils.Path.compareDesc(this.canonicalPath, that.getCanonicalPath) == 0
	def sameResource(that: String): Boolean = sameResource(Resource(that))
	override def toString: String = getType + "(" + super.toString + ")"
	def getType: String
	def isSoft: Boolean = !isHard
	def isHard: Boolean

	final def getResource: Resource = this.asInstanceOf[Resource]
}

object Dependency{
	def dependency2ordered(d: Dependency): Ordered[Dependency] = new Ordered[Dependency]{
		def compare(that: Dependency): Int = {
			val lex: Int = d compare that
			if(lex != 0)
				lex
			else if(d.isInstanceOf[HardDependency])
				-1
			else
				1
		}
	}

	def orderDependencies(deps: Iterable[Dependency]) = {
		import scala.collection.immutable.TreeSet
		(new TreeSet[Dependency]()(dependency2ordered _)) ++ deps
	}
}


//case classes?
abstract case class HardDependency(p: String) extends Dependency(p){
	private def this() = this(".")
//	def this(path: String) = this(Resource(path))
  def lacks: Boolean = !exists
	override def equals(that: Any): Boolean = 
		that.isInstanceOf[HardDependency] && super.equals(that)
	//override def toString: String = "HardDependency(" + super.toString + ")"
	override def getType: String = HardDependency.dependencyType
	override def isHard: Boolean = true
}

object HardDependency{
	lazy val dependencyType: String = "HardDependency"
	//todo: 2 scalab runs => 2 object creations => avoid strange things with maps
	private[core] lazy val allHardDependencies: HashMap[Pathname, HardDependency] = new HashMap[Pathname, HardDependency]
	def apply(p: String): HardDependency = {
		val h: HardDependency = new HardDependency(p){}
		val pathname = Pathname(h.canonicalPath)
		allHardDependencies.get(pathname) match{
			case Some(dep) => dep
			case None => 
				allHardDependencies.update(pathname, h)
				h
		}
	}

	def apply(baseDir: String, paths: Iterable[String]): Iterable[HardDependency] = paths map {p => apply(baseDir + p)}
	def apply(baseDir: String, paths: String*): Iterable[HardDependency] = apply(baseDir, paths)
	def apply(d: File): HardDependency = apply(d.getPath)
	def apply(files: Iterable[File]): Iterable[HardDependency] = files map {f => apply(f)}
	def apply(files: File*): Iterable[HardDependency] = apply(files)
}

abstract case class SoftDependency(p: String) extends Dependency(p){
	private def this() = this(".")
//	def this(path: String) = this(Resource(path))
  def lacks: Boolean = false
	override def equals(that: Any): Boolean = 
		that.isInstanceOf[SoftDependency] && super.equals(that)
	//override def toString: String = "SoftDependency(" + super.toString + ")"
	override def getType: String = SoftDependency.dependencyType
	override def isHard: Boolean = false
}

object SoftDependency{
	lazy val dependencyType: String = "SoftDependency"
	private[core] lazy val allSoftDependencies: HashMap[Pathname, SoftDependency] = new HashMap[Pathname, SoftDependency]
	def apply(p: String): SoftDependency = {
		val s: SoftDependency = new SoftDependency(p){}
		val pathname = Pathname(s.canonicalPath)
		allSoftDependencies.get(pathname) match{
			case Some(dep) => dep
			case None => 
				allSoftDependencies.update(pathname, s)
				s
		}
	}

	def apply(baseDir: String, paths: Iterable[String]): Iterable[SoftDependency] = paths map {p => apply(baseDir + p)}
	def apply(baseDir: String, paths: String*): Iterable[SoftDependency] = apply(baseDir, paths)
	def apply(file: File): SoftDependency = apply(file.getPath)
	def apply(files: Iterable[File]): Iterable[SoftDependency] = files map {f => apply(f)}
	def apply(files: File*): Iterable[SoftDependency] = apply(files)
}




